package com.dl.utils;

import com.dl.properties.PathProperties;
import org.junit.Test;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * ffmpeg工具类
 * 2021年4月24日15:39:40
 */
@EnableConfigurationProperties(PathProperties.class)
public class FfmpegUtils {

    @Resource
    static private PathProperties pathProperties;

    //static ResourceBundle resourceBundle = ResourceBundle.getBundle("application");//获取配置，不需要写后缀名
    //public final static String ffmpegPath = resourceBundle.getString("ffmpegPath");

    public final static String ffmpegPath = pathProperties.getFfmpegPath();


    public static void getVideoCover(String ffmpegPath, String videoPath, String name) throws IOException {
        int videoTime = getVideoTime(ffmpegPath, videoPath);
        getVideoCover(ffmpegPath,videoPath,name,videoTime);
    }

    /**
     * 获取第三帧的缩略图 -- （cmd(windows): ffmpeg.exe -ss 00:00:03 -y -i test1.mp4 -vframes 1 new.jpg）
     * @param ffmpegPath      ffmpeg.exe文件路径，可在rest或者admin中进行配置，使用配置文件进行读取
     * @param videoPath  视频文件路径（输入）
     * @param name 缩略图名称
     */
    public static void getVideoCover(String ffmpegPath, String videoPath, String name, int videoTime) throws IOException {

        String timeStr = DateUtils.secToTime(videoTime / 2);//根据视频时长获得中间部位
        // 构建命令
        List<String> command = new ArrayList<>();
        //获取路径
        String outputPath = videoPath.substring(0,videoPath.lastIndexOf("\\"));

        command.add(ffmpegPath);
        command.add("-ss");
        command.add(timeStr);//截取第几秒的视频 格式：00:00:00
        command.add("-y");
        command.add("-i");
        command.add(videoPath);
        command.add("-vframes");
        command.add("1");
        command.add(outputPath + "\\" + name);
        // 执行操作
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.start();
        InputStream errorStream = process.getErrorStream();
        InputStreamReader isr = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(isr);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        br.close();
        isr.close();
        errorStream.close();
    }

    public static int getThumbnail(String ffmpegPath, String videoPath) throws IOException {
        return getThumbnail(ffmpegPath,videoPath,getVideoTime(ffmpegPath,videoPath));
    }

    /**
     * 获取缩略图 -- （cmd(windows): ffmpeg -i video.mp4 -vsync vfr -vf "select=isnan(prev_selected_t)+gte(t-prev_selected_t\,1),scale=160:90,tile=10x10" -qscale:v 3 "thumbnail.jpg"）
     * 进度截图默认存放当前视频文件夹，名称thumbnail1.jpg...
     * ffmpeg -i video.mp4 -vf "select='eq(pict_type,PICT_TYPE_I)'" -vsync vfr thumb%04d.png
     * ffmpeg -i video.mp4 -vsync vfr -vf "select=isnan(prev_selected_t)+gte(t-prev_selected_t\,1),scale=160:90,tile=10x10" -qscale:v 3 "thumbnail.jpg"）
     * @param ffmpegPath     ffmpeg.exe文件路径，可在rest或者admin中进行配置，使用配置文件进行读取
     * @param videoPath      视频文件路径
     */
    public static int getThumbnail(String ffmpegPath, String videoPath, int videoTime) throws IOException {
        // 构建命令
        List<String> command = new ArrayList<>();
        //获取路径
        String outputPath = videoPath.substring(0,videoPath.lastIndexOf("\\") + 1);
        int x = 1;//间隔几秒截一张图
        //获取生成的图片张数
        int total = (videoTime % 100 == 0 ? videoTime / 100 : videoTime / 100 + 1);

        command.add(ffmpegPath);
        command.add("-i");
        command.add(videoPath);
        command.add("-vsync");
        command.add("vfr");
        command.add("-vf");
        command.add("select=isnan(prev_selected_t)+gte(t-prev_selected_t\\," + x + "),scale=160:90,tile=10x10");
        command.add("-qscale:v");
        command.add("3");
        command.add(outputPath + "thumbnail%d.jpg");

        //使用多线程进行操作节省时间
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    ProcessBuilder builder = new ProcessBuilder(command);
                    Process process = builder.start();
                    InputStream errorStream = process.getErrorStream();
                    InputStreamReader isr = new InputStreamReader(errorStream);
                    BufferedReader br = new BufferedReader(isr);
                    br.close();
                    isr.close();
                    errorStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        };
        new Thread(runnable).start();

        return total;
    }

    @Test
    public void testGetThumbnail() {
        try {
            String videoPath = "E:\\Users\\123\\Desktop\\test\\123.mp4";
            int total = FfmpegUtils.getThumbnail(ffmpegPath, videoPath);
            System.out.println("total = " + total);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testGetVideoCover() {
        try {
            FfmpegUtils.getVideoCover(ffmpegPath,
                                    "F:\\DL\\SSM框架\\学校\\mvc\\FfmpegDemo-05-json\\target\\FfmpegDemo-05-json-1.0\\upload\\a13b805b\\123.mp4",
                                    "F:\\DL\\SSM框架\\学校\\mvc\\FfmpegDemo-05-json\\target\\FfmpegDemo-05-json-1.0\\upload\\a13b805b\\new.jpg");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 简易视频处理 -- （cmd(windows): ffmpeg.exe -i test1.mp4 newVideo.avi）
     *
     * @param ffmpegPath      ffmpeg.exe文件路径，可在rest或者admin中进行配置，使用配置文件进行读取
     * @param videoInputPath  视频文件路径（输入）
     * @param videoOutputPath 转换完成的文件路径（输出）
     */
    public static void videoConvert(String ffmpegPath, String videoInputPath, String videoOutputPath) throws IOException {
        // 构建命令
        List<String> command = new ArrayList<>();
        command.add(ffmpegPath);
        command.add("-i");
        command.add(videoInputPath);
        command.add(videoOutputPath);
        // 执行操作
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.start();
        InputStream errorStream = process.getErrorStream();
        InputStreamReader isr = new InputStreamReader(errorStream);
        BufferedReader br = new BufferedReader(isr);
        String line = "";
        while ((line = br.readLine()) != null) {
        }
        br.close();
        isr.close();
        errorStream.close();
    }


    @Test
    public void testGetVideoTime() {
        //int videoTime = FfmpegUtils.getVideoTime(ffmpegPath, "G:\\白蛇缘起\\白蛇缘起.mp4");
        int videoTime = 1305;
        System.out.println("videoTime = " + videoTime);
        System.out.println("videoTime / 100 = " + videoTime / 100);
        System.out.println("videoTime % 100 = " + videoTime % 100);

    }

    /**
     * 获取视频总时间
     * @param videoPath    视频路径
     * @param ffmpegPath	ffmpeg路径
     */
    public static int getVideoTime(String ffmpegPath, String videoPath) throws IOException {
        List<String> commands = new ArrayList<String>();
        commands.add(ffmpegPath);
        commands.add("-i");
        commands.add(videoPath);
        ProcessBuilder builder = new ProcessBuilder();
        builder.command(commands);
        final Process p = builder.start();

        //从输入流中读取视频信息
        BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        StringBuffer sb = new StringBuffer();
        String line = "";
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();

        //从视频信息中解析时长
        String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s";
        Pattern pattern = Pattern.compile(regexDuration);
        Matcher m = pattern.matcher(sb.toString());
        int time = 0;
        if (m.find()) {
            time = calculateTime(m.group(1));
            System.out.println("视频时长："+time+"s, 开始时间："+m.group(2)+",比特率："+m.group(3)+"kb/s");
            return time;
        }

        return -1;
    }

    //格式:"00:00:10.68"
    private static int calculateTime(String timelen){
        int min=0;
        String[] strs = timelen.split(":");
        if (strs[0].compareTo("0") > 0) {
            min+=Integer.parseInt(strs[0])*60*60;//秒
        }
        if(strs[1].compareTo("0")>0){
            min+=Integer.parseInt(strs[1])*60;
        }
        if(strs[2].compareTo("0")>0){
            min+=Math.round(Float.parseFloat(strs[2]));
        }
        return min;
    }

}
